using System;
using System.IO;
using System.Text;

namespace Gazebo.Util
{
    public class Chunker
    {
        private string prompt = "fics% ";
        
        public string Prompt {
            get { return prompt; }
            set {
                if (value == null)
                    throw new ArgumentNullException();
                
                if (value.Length == 0)
                    throw new ArgumentException("value.Length == 0");
                
                prompt = value;
            }
        }
        
        private StringBuilder buffer = new StringBuilder();
        
        public ChunkMode ChunkMode { get; set; }
        
        public Chunker()
        {
            ChunkMode = ChunkMode.Smart;
        }
        
        public void Append(char[] buf, int offset, int length) {
            for (int i = offset; i < offset + length; i++) {
                if (buf[i] != '\r') {
                    buffer.Append(buf[i]);
                }
            }
        }
        
        private bool StringAt(int index, string str, out int end) {
            end = 0;
            
            if (index + str.Length > buffer.Length)
                return false;
            
            for (int i = 0; i < str.Length; i++) {
                if (buffer[index + i] != str[i])
                    return false;
            }
            
            end = index + str.Length;
            
            return true;
        }
        
        private bool IsSmartPrompt(int index, out int end) {
            if (StringAt(index, prompt, out end))
                return true;
            
            if (buffer.Length - index < 6 + prompt.Length)
                return false;
            
            if (!char.IsDigit(buffer[index]) ||
                !char.IsDigit(buffer[index + 1]) ||
                buffer[index + 2] != ':' ||
                !char.IsDigit(buffer[index + 3]) ||
                !char.IsDigit(buffer[index + 4]) ||
                buffer[index + 5] != '_')
                return false;
            
            return StringAt(index + 6, prompt, out end);
        }
        
        public string NextChunk() {
            if (ChunkMode == ChunkMode.None) {
                if (buffer.Length == 0) {
                    return null;
                }
                
                string chunk = buffer.ToString();
                buffer.Length = 0;
                
                return chunk;
            }
            
            for (int i = -1; i < buffer.Length; i++) {
                if (i == -1 || buffer[i] == '\n') {
                    bool found = false;
                    int end = 0;
                    
                    switch (ChunkMode) {
                    case ChunkMode.Prompt:
                        found = StringAt(i + 1, prompt, out end);
                        break;
                        
                    case ChunkMode.Smart:
                        found = IsSmartPrompt(i + 1, out end);
                        break;
                    }
                    
                    if (found) {
	                    string chunk = buffer.ToString(0, i + 1);
	                    
	                    string rest = buffer.ToString(end, buffer.Length - end);
                        
	                    buffer.Length = 0;
	                    buffer.Append(rest);
	                    
	                    return chunk;
                    }
                }
            }
            
            return null;
        }
    }
}
